package edu.up.firesawakening;

import edu.up.firesawakening.TacticsGame.Move;
import edu.up.game.R;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.SurfaceView;

/**
 * A surface view that draws the current game state
 * 
 * @author Matt Delaney
 * @author Viet Phan
 * @author Alex Hanemann
 */
public class TacticsSurfaceView extends SurfaceView {

	/**
	 * Size of a tile on the board
	 */
	public static final int TILE_SIZE = 75;

	// distance to offset the unit drawings by
	public static final int UNIT_OFFSET = 16;
	public static final int CASTLE_OFFSET = 7;

	protected int m_dispTilesX = 8;
	protected int m_dispTilesY = 8;

	/**
	 * The map to draw
	 */
	protected Tile[][] map;

	/**
	 * The currently selected tile
	 */
	protected Tile m_selected;

	/**
	 * The current target tile
	 */
	protected Tile m_target;

	/**
	 * X coord of display
	 */
	protected int upperLeftX;

	/**
	 * Y coord of display
	 */
	protected int upperLeftY;

	/**
	 * High index of x tiles to display
	 */
	protected int maxX;

	/**
	 * High index of y tiles to display
	 */
	protected int maxY;

	/**
	 * The overlay to draw
	 */
	protected Move[][] dispMove;

	/**
	 * Paint for drawing outlines on the map
	 */
	protected Paint outlinePaint;

	/**
	 * Paint for drawing moves on the map
	 */
	protected Paint movePaint;

	/**
	 * Paint for drawing attacks on the map
	 */
	protected Paint attackPaint;

	/**
	 * Paint for drawing overlay on friends on the map
	 */
	protected Paint friendPaint;

	/**
	 * Paint for highlighting a border around a tile
	 */
	protected Paint selectPaint;

	protected Paint destTilePaint;

	/**
	 * Used to draw the tiles
	 */
	protected Rect box;

	// Used to display images
	// Tile files
	protected Bitmap m_mountainTile, m_plainsTile, m_riverTile;
	// Unit files
	protected Bitmap m_basicUnitPlayer0, m_castlePlayer0, m_rangedPlayer0;
	protected Bitmap m_basicUnitPlayer1, m_castlePlayer1, m_rangedPlayer1;

	// debug
	protected Paint fillPaint, circlePaint;

	public int getDispXTiles() {
		return m_dispTilesX;
	}

	public int getDispYTiles() {
		return m_dispTilesY;
	}

	/**
	 * @param context
	 */
	public TacticsSurfaceView(Context context) {
		super(context);
		init();

	}

	/**
	 * @param context
	 * @param attrs
	 */
	public TacticsSurfaceView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}

	/**
	 * @param context
	 * @param attrs
	 * @param defStyle
	 */
	public TacticsSurfaceView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init();
	}

	/**
	 * Sets up the variables the surface view will need
	 */
	protected void init() {

		outlinePaint = new Paint();
		outlinePaint.setColor(Color.BLACK);
		outlinePaint.setStyle(Style.STROKE);
		outlinePaint.setStrokeWidth(2f);

		// Paint for overlay
		Paint overlayPaint = new Paint();
		overlayPaint.setStyle(Style.FILL);

		movePaint = new Paint(overlayPaint);
		movePaint.setColor(Color.argb(150, 255, 255, 0));

		attackPaint = new Paint(overlayPaint);
		attackPaint.setColor(Color.argb(150, 255, 0, 0));

		friendPaint = new Paint(overlayPaint);
		friendPaint.setColor(Color.argb(150, 0, 255, 0));

		selectPaint = new Paint();
		selectPaint.setColor(Color.GREEN);
		selectPaint.setStyle(Style.STROKE);
		selectPaint.setStrokeWidth(6f);

		// Paints for tile types
		fillPaint = new Paint(outlinePaint);
		fillPaint.setStyle(Style.FILL);

		// Image files
		this.m_mountainTile = BitmapFactory.decodeResource(getResources(),
				R.drawable.tilemountain);
		m_riverTile = BitmapFactory.decodeResource(getResources(),
				R.drawable.tileriver);
		m_plainsTile = BitmapFactory.decodeResource(getResources(),
				R.drawable.tileplains);

		m_basicUnitPlayer0 = BitmapFactory.decodeResource(getResources(),
				R.drawable.unitbasicblue);
		m_castlePlayer0 = BitmapFactory.decodeResource(getResources(),
				R.drawable.unitcastleblue);
		m_rangedPlayer0 = BitmapFactory.decodeResource(getResources(),
				R.drawable.unitrangedblue);

		m_basicUnitPlayer1 = BitmapFactory.decodeResource(getResources(),
				R.drawable.unitbasicred);
		m_castlePlayer1 = BitmapFactory.decodeResource(getResources(),
				R.drawable.unitcastlered);
		m_rangedPlayer1 = BitmapFactory.decodeResource(getResources(),
				R.drawable.unitrangedred);

		// debug
		circlePaint = new Paint();

		box = new Rect();
	}

	@Override
	public void onSizeChanged(int w, int h, int oldw, int oldh) {
		super.onSizeChanged(w, h, oldw, oldh);

		if (w == 0 || h == 0)
			return;

		this.updateDispTileXY();
		this.updateTSV(map, dispMove, m_selected, m_target, upperLeftX,
				upperLeftY);
		invalidate();
	}

	/**
	 * Updates map and overlay and redraws
	 * 
	 * @param mapIn
	 *            the map to display
	 * @param dispIn
	 *            the overlay to display
	 */
	public void updateTSV(Tile[][] mapIn, Move[][] dispIn, Tile selected,
			Tile target, int x, int y) {
		// store new values
		map = mapIn;
		dispMove = dispIn;
		m_selected = selected;
		m_target = target;
		upperLeftX = x;
		upperLeftY = y;

		// make sure we're trying to display valid tiles
		if (upperLeftX < 0)
			upperLeftX = 0;

		if (upperLeftY < 0)
			upperLeftY = 0;

		maxX = upperLeftX + m_dispTilesX;
		maxY = upperLeftY + m_dispTilesY;

		if (maxX > map.length || upperLeftX > map.length) {
			maxX = map.length;
			upperLeftX = maxX - m_dispTilesX;
		}

		if (maxY > map[0].length || upperLeftY > map[0].length) {
			maxY = map[0].length;
			upperLeftY = maxY - m_dispTilesY;
		}

		// make sure we're trying to display valid tiles
		if (upperLeftX < 0)
			upperLeftX = 0;

		if (upperLeftY < 0)
			upperLeftY = 0;

		invalidate();
	}

	/**
	 * updates the display tiles based on the current TSV.
	 */
	protected void updateDispTileXY() {
		// calculate new screen width
		int boxLeftX, boxRightX, boxTopY, boxBottomY;
		boxLeftX = this.getLeft();
		boxRightX = this.getRight();
		boxTopY = this.getTop();
		boxBottomY = this.getBottom();

		// make sure this isn't the first hit of the method (before the TSV has
		// a coordinate size)
		if (boxRightX != 0 && boxBottomY != 0 && boxRightX > boxLeftX
				&& boxBottomY > boxTopY) {
			m_dispTilesX = (boxRightX - boxLeftX) / TILE_SIZE;
			m_dispTilesY = (boxBottomY - boxTopY) / TILE_SIZE;
		}

		if (m_dispTilesX > map.length)
			m_dispTilesX = map.length;

		if (m_dispTilesY > map[0].length)
			m_dispTilesY = map[0].length;
	}

	/**
	 * Draws the game board and its current state
	 * 
	 * 
	 * 
	 * @param canvas
	 *            to draw on
	 */
	@Override
	public void draw(Canvas canvas) {
		// If we have no map, nothing to do here
		if (map == null) {
			return;
		}

		// Draw the outline of the board
		for (int x = upperLeftX; x < maxX; x++) {
			for (int y = upperLeftY; y < maxY; y++) {

				int currX = TILE_SIZE * (x - upperLeftX);
				int currY = TILE_SIZE * (y - upperLeftY);

				box.set(currX, currY, currX + TILE_SIZE, currY + TILE_SIZE);

				canvas.drawRect(box, outlinePaint);
			}
		}
		// Draw the terrain, overlay, and units
		for (int x = upperLeftX; x < maxX; x++) {
			for (int y = upperLeftY; y < maxY; y++) {

				int currX = TILE_SIZE * (x - upperLeftX);
				int currY = TILE_SIZE * (y - upperLeftY);

				box.set(currX, currY, currX + TILE_SIZE, currY + TILE_SIZE);

				// Draw terrain
				switch (map[x][y].getType()) {
				case MOUNTAIN:
					canvas.drawBitmap(m_mountainTile, currX, currY, null);
					break;
				case PLAINS:
					canvas.drawBitmap(m_plainsTile, currX, currY, null);
					break;
				case RIVER:
					canvas.drawBitmap(m_riverTile, currX, currY, null);
					break;
				default:
					canvas.drawBitmap(m_plainsTile, currX, currY, null);
					break;
				}

				// Draw overlay
				if (dispMove != null && dispMove[x][y] != null) {
					switch (dispMove[x][y].move) {
					case MOVE:
						canvas.drawRect(box, movePaint);
						break;
					case EMPTY_ATTACK:
					case ATTACK:
						canvas.drawRect(box, attackPaint);
						break;
					case PASS:
						canvas.drawRect(box, friendPaint);
						break;
					default:
						break;
					}
				}

				// Draw unit, if one is present
				if (map[x][y].isOccupied()) {
					switch (map[x][y].getUnit().getOwner()) {
					// player 0:
					case 0:
						if (map[x][y].getUnit() instanceof Castle) {
							// draw castle
							canvas.drawBitmap(m_castlePlayer0, currX
									+ CASTLE_OFFSET, currY + CASTLE_OFFSET,
									null);
						} else if (map[x][y].getUnit() instanceof RangedUnit) {
							canvas.drawBitmap(m_rangedPlayer0, currX
									+ UNIT_OFFSET, currY + UNIT_OFFSET, null);
						}

						else {
							// draw unit
							canvas.drawBitmap(m_basicUnitPlayer0, currX
									+ UNIT_OFFSET, currY + UNIT_OFFSET, null);
						}
						break;

					// player 1:
					case 1:
						if (map[x][y].getUnit() instanceof Castle) {
							// draw castle
							canvas.drawBitmap(m_castlePlayer1, currX
									+ CASTLE_OFFSET, currY + CASTLE_OFFSET,
									null);
						} else if (map[x][y].getUnit() instanceof RangedUnit) {
							canvas.drawBitmap(m_rangedPlayer1, currX
									+ UNIT_OFFSET, currY + UNIT_OFFSET, null);
						} else {
							// draw unit
							canvas.drawBitmap(m_basicUnitPlayer1, currX
									+ UNIT_OFFSET, currY + UNIT_OFFSET, null);
						}
						break;
					}
				}
			}
		}

		// highlight the selected tiles if there are any
		if (m_selected != null && m_selected.getX() >= upperLeftX
				&& m_selected.getY() >= upperLeftY && m_selected.getX() < maxX
				&& m_selected.getY() < maxY) {
			box.set((m_selected.getX() - upperLeftX) * TILE_SIZE,
					(m_selected.getY() - upperLeftY) * TILE_SIZE,
					((m_selected.getX() - upperLeftX) + 1) * TILE_SIZE,
					((m_selected.getY() - upperLeftY) + 1) * TILE_SIZE);
			canvas.drawRect(box, selectPaint);
		}

		if (m_target != null && m_target.getX() >= upperLeftX
				&& m_target.getY() >= upperLeftY && m_target.getX() < maxX
				&& m_target.getY() < maxY) {
			box.set((m_target.getX() - upperLeftX) * TILE_SIZE,
					(m_target.getY() - upperLeftY) * TILE_SIZE,
					((m_target.getX() - upperLeftX) + 1) * TILE_SIZE,
					((m_target.getY() - upperLeftY) + 1) * TILE_SIZE);
			canvas.drawRect(box, selectPaint);
		}

	}

}
